//
// * Copyright (c) 2002-2009 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
namespace org.neo4j.kernel.impl.nioneo.store
{


///
/// <summary> * Wraps a <CODE>ByteBuffer</CODE> and is tied to a <seealso cref="PersistenceWindow"/>.
/// * Using the <seealso cref="#setOffset(int)"/> method one can offset the buffer (within
/// * the limits of the persistence window.
/// * <p>
/// * All the <CODE>put</CODE> and <CODE>get</CODE> methods of this class works
/// * the same way as in <CODE>ByteBuffer</CODE>.
/// *  </summary>
/// * <seealso cref= ByteBuffer, PersistenceWindow </seealso>
/// 
	public class Buffer
	{
		private static Logger logger = Logger.getLogger(typeof(Buffer).Name);

		private ByteBuffer buf = null;
		private readonly PersistenceWindow persistenceWindow;

		internal Buffer(PersistenceWindow persistenceWindow)
		{
			this.persistenceWindow = persistenceWindow;
		}

		internal virtual void setByteBuffer(ByteBuffer byteBuffer)
		{
			this.buf = byteBuffer;
		}

///    
///     <summary> * Returns the position of the persistence window tied to this buffer.
///     *  </summary>
///     * <returns> The persistence window's position </returns>
///     
		public virtual long position()
		{
			return persistenceWindow.position();
		}

///    
///     <summary> * Returns the underlying byte buffer.
///     *  </summary>
///     * <returns> The byte buffer wrapped by this buffer </returns>
///     
		public virtual ByteBuffer getBuffer()
		{
			return buf;
		}

///    
///     <summary> * Sets the offset from persistence window position in the underlying byte
///     * buffer.
///     *  </summary>
///     * <param name="offset">
///     *            The new offset to set </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer setOffset(int offset)
		{
			try
			{
				buf.position(offset);
			}
			catch (java.lang.IllegalArgumentException e)
			{
				logger.severe("Illegal buffer position: Pos=" + position() + " off=" + offset + " capacity=" + buf.capacity());
				throw e;
			}
			return this;
		}

///    
///     <summary> * Returns the offset of this buffer.
///     *  </summary>
///     * <returns> The offset </returns>
///     
		public virtual int getOffset()
		{
			return buf.position();
		}

///    
///     <summary> * Puts a <CODE>byte</CODE> into the underlying buffer.
///     *  </summary>
///     * <param name="b">
///     *            The <CODE>byte</CODE> that will be written </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer put(sbyte b)
		{
			buf.put(b);
			return this;
		}

///    
///     <summary> * Puts a <CODE>int</CODE> into the underlying buffer.
///     *  </summary>
///     * <param name="i">
///     *            The <CODE>int</CODE> that will be written </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer putInt(int i)
		{
			buf.putInt(i);
			return this;
		}

///    
///     <summary> * Puts a <CODE>long</CODE> into the underlying buffer.
///     *  </summary>
///     * <param name="l">
///     *            The <CODE>long</CODE> that will be written </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer putLong(long l)
		{
			buf.putLong(l);
			return this;
		}

///    
///     <summary> * Reads and returns a <CODE>byte</CODE> from the underlying buffer.
///     *  </summary>
///     * <returns> The <CODE>byte</CODE> value at the current position/offset </returns>
///     
		public virtual sbyte @get()
		{
			return buf.get();
		}

///    
///     <summary> * Reads and returns a <CODE>int</CODE> from the underlying buffer.
///     *  </summary>
///     * <returns> The <CODE>int</CODE> value at the current position/offset </returns>
///     
		public virtual int getInt()
		{
			return buf.getInt();
		}

///    
///     <summary> * Reads and returns a <CODE>long</CODE> from the underlying buffer.
///     *  </summary>
///     * <returns> The <CODE>long</CODE> value at the current position/offset </returns>
///     
		public virtual long getLong()
		{
			return buf.getLong();
		}

///    
///     <summary> * Puts a <CODE>byte array</CODE> into the underlying buffer.
///     *  </summary>
///     * <param name="src">
///     *            The <CODE>byte array</CODE> that will be written </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer put(sbyte[] src)
		{
			buf.put(src);
			return this;
		}

		public virtual Buffer put(char[] src)
		{
			int oldPos = buf.position();
			buf.asCharBuffer().put(src);
			buf.position(oldPos + src.Length * 2);
			return this;
		}

///    
///     <summary> * Puts a <CODE>byte array</CODE> into the underlying buffer starting from
///     * <CODE>offset</CODE> in the array and writing <CODE>length</CODE>
///     * values.
///     *  </summary>
///     * <param name="src">
///     *            The <CODE>byte array</CODE> to write values from </param>
///     * <param name="offset">
///     *            The offset in the <CODE>byte array</CODE> </param>
///     * <param name="length">
///     *            The number of bytes to write </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer put(sbyte[] src, int offset, int length)
		{
			buf.put(src, offset, length);
			return this;
		}

///    
///     <summary> * Reads <CODE>byte array length</CODE> bytes into the 
///     * <CODE>byte array</CODE> from the underlying buffer.
///     *  </summary>
///     * <param name="dst">
///     *            The byte array to read values into </param>
///     * <returns> This buffer </returns>
///     
		public virtual Buffer @get(sbyte[] dst)
		{
			buf.get(dst);
			return this;
		}

		public virtual Buffer @get(char[] dst)
		{
			buf.asCharBuffer().get(dst);
			return this;
		}

		public virtual void close()
		{
			buf = null;
		}

		public override string ToString()
		{
			return "Buffer[[" + buf.position() + "," + buf.capacity() + "]," + persistenceWindow + "]";
		}
	}
}